目錄
使用 S3 來儲存照片可以很容易的建立一個無服務器的應用,只要結合 API Gateway 與 AWS Lambda 就可以讓使用者在不需建置任何服務器的情況下,提供一個照片存放的功能,本實驗將提供這樣的整合練習:API Gateway+Lambda+S3
AWS Academy Learner Lab 是提供一個帳號讓學生可以自行使用 AWS 的服務,讓學生可以在 50 USD的金額下,自行練習所要使用的 AWS 服務,在此先介紹一下 Learner Lab 基本操作與限制。
在 AWS Academy 學習平台 的入口首頁 https://www.awsacademy.com/LMS_Login ,選擇以學生 (Students) 身分登錄,在課程選單中選擇 AWS Academy Learner Lab - Foundation Services 的課程,在課程選單中選擇 單元 (Module),接著單擊 啟動 AWS Academy Learner Lab,如下圖所示。
圖 1. 啟動 AWS Academy Learner Lab
進入 Learner Lab 中,說明一下每個區塊,圖形在下方。
圖 2. Learner Lab 畫面說明
AWS Cloud9 IDE 畫面與 VS Code 畫面相似,左手邊是功能視窗,可以檢視檔案與其他功能;,右上方是檔案編輯畫面,可以進行檔案編輯,撰寫程式進行 AWS SDK 操作;右下方則是終端命令列介面,可以輸入指令,進行 AWS CLI 操作。
圖 3. AWS Cloud9 IDE
在下方的終端輸入以下指令,取得實驗所需要的資源,可以在左上角看到已下載的檔案。
git clone https://github.com/yehchitsai/AIoTnAWSCloud
圖 4. 取得實驗所需要的資源
輸入以下 AWS CLI 指令,用來建立 S3 儲存貯體,將 BUCKET_NAME
改為自己所要建立的 S3 儲存貯體名稱。aws s3api create-bucket --bucket BUCKET_NAME
AWS CLI 說明指令:aws [options] <command> <subcommand> [parameters]
而回傳值是建立儲存貯體的名稱。
圖 5. 使用 AWS CLI 指令建立 S3 儲存貯體
注意:儲存貯體的名稱是全球唯一的,所以每個人都要取不同的名稱。
打開 s3_security_policy.json 檔案,將 BUCKET_NAME 改成自己所建立的儲存貯體的名稱,MY_PUBLIC_IP 則是要上網查找自己電腦的公開ip,這可能會跟自己電腦上所設定的ip不同,因為大多數情況,上網都是多人共用一個公開ip,如下圖所示。
圖 6. 查找自己電腦的公開 IP
{
"Version": "2008-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": [
"arn:aws:s3:::BUCKET_NAME/*",
"arn:aws:s3:::BUCKET_NAME"
],
"Condition": {
"IpAddress": {
"aws:SourceIp": "MY_PUBLIC_IP/32"
}
}
}
]
}
修改完畢後,接著修改 permissions.py 的 BUCKET_NAME 自己所建立的儲存貯體的名稱,接著執行,就可以在新的儲存貯體上設定政策,讓自己的電腦可以用靜態網站的方式使用 S3。
import boto3
import json
import pathlib
s3_client = boto3.client("s3", region_name="us-east-1")
bucket_name = "BUCKET_NAME"
current_path = str(pathlib.Path(__file__).parent.resolve())
policy_file = open(current_path + "/dataset/s3_security_policy.json", "r")
s3_client.put_bucket_policy(
Bucket = bucket_name,
Policy = policy_file.read()
)
圖 7. 使用 Python SDK 為儲存貯體設定儲存貯體策略
接著可以到 S3 控制台,檢視 S3 儲存貯體策略。
圖 8. 檢視 S3 儲存貯體策略
將物件上傳到儲存貯體以建立網站,將 BUCKET_NAME
改為自己建立的 S3 儲存貯體名稱。
aws s3 cp AIoTnAWSCloud/lab/website s3://BUCKET_NAME/ --recursive --cache-control "max-age=0"
圖 9. 物件上傳到儲存貯體
在 S3 儲存貯體中到找到首頁 show_s3_image.html ,點選後在屬性頁籤找到物件 URL,複製起來打開一個空白網頁。
圖 10. 取得首頁的進入網址
貼上網址後,就可以檢視網頁成果,沒有圖片只有文字。
圖 11. 檢視網頁
進入 Lambda 控制台,建立一個新的 AWS Lambda 函數,配置如下:
圖 12. 建立 AWS Lambda 函數
在 Lambda 函數中撰寫要運行的程式碼,在程式碼頁簽中程式碼來源撰寫測試的程式。
因為這次程式的功能為讀取用戶透過 HTTP POST 請求所傳遞過來的圖片,圖片內容已經事先轉換成 base64 格式,收到 base64 格式的字符串後,轉換成圖片,並上傳到 S3 ,代碼如下:
將 BUCKET_NAME
改為自己所建立的 S3 儲存貯體名稱。
import json
import base64
import boto3
# 存放圖片的 S3 存儲桶
output_bucket = 'BUCKET_NAME'
# 存放在 S3 存儲桶中的檔案名稱
s3_key_value = 'apigateway2S3.jpg'
s3_client = boto3.client('s3')
def lambda_handler(event, context):
requestMethod = event['httpMethod']
# HTTP 請求方式為 POST 才做後續處理
if requestMethod=='POST':
# 將上傳的 JSON 字符串轉換成字典
requestBody = json.loads(event['body'])
# 將上傳的 base64 字符串轉換成字組,再轉換成 binary 格式
image_64_decode = base64.decodebytes(requestBody['key'].encode())
# 上傳到 S3 存儲桶
response = s3_client.put_object(
Body=image_64_decode,
Bucket=output_bucket,
Key=f'{s3_key_value}',
)
s3_url = 'https://' + output_bucket + '.s3.amazonaws.com/' + s3_key_value
return {
'statusCode': 200,
'body': s3_url
}
else:
# HTTP 請求方式非 POST 回傳錯誤
return {
'statusCode': 200,
'body': 'method error'
}
圖 13. AWS Lambda 函數程式碼
編寫完成程式碼之後,由於還沒有部署,無法進行測試或者調用。部署類似於將程式碼同步到 Lambda 函數中,部署程式碼,點擊 Deploy,撰寫完程式碼之後需要部署程式碼,之後才能進行測試。
在 Lambda 主畫面上方找到添加觸發器按鈕,如下圖所示。
圖 14. 在 Lambda 主畫面中進行添加觸發器
進入添加觸發器畫面,配置如下:
添加觸發器
圖 15. 在添加觸發器畫面中進行 API Gateway 配置
添加觸發器後可以在配置中查看觸發器的結果,取得 API 終端節點,如下圖所示。
圖 16. 取得 API 終端節點
因為程式碼需要讀取使用者傳來的資料,所以需要用 POSTMAN 來傳圖片資料,而圖片資料需要轉換成 base64 格式,所以需要撰寫額外的程式碼來進行轉換,進入 Cloude9 打開 encode_image.py 程式,它會將 python 目錄中的 yehchitsai.jpg 圖片進行編碼,並將結果存在 base64.txt
# convert base64 to image
import base64
import pathlib
current_path = str(pathlib.Path(__file__).parent.resolve())
image = open(current_path + '/images/yehchitsai.jpg', 'rb')
image_read = image.read()
image_64_encode = base64.encodebytes(image_read)
# print(image_64_encode)
image_encode_file = open(f'{current_path}/base64.txt','w')
image_encode_file.write(str(image_64_encode))
image_encode_file.close()
執行完上述程式後,它會將base64的資料存在base64.txt中,複製 b' 這裡的資料,不包含前後單引號 '
圖 17. 取得圖片的base64編碼
接著使用常見的 API 測試軟件來進行測試,在本機端打開 Postman,並輸入相關的配置。
接著點擊送出 Send 就得到完整的請求信息響應 (Response),即為上傳到 S3 的網址。
圖 18. 取得圖片的 S3 的網址
進入 Cloud9 修改 show_s3_image.html 網頁所指定的圖片所在位置,改為圖片的 S3 的網址,並將網頁上傳到 S3,如下圖所示。
將該網頁上傳到 S3 上,在下方的終端畫面輸入以下指令,將 BUCKET_NAME
改為自己建立的 S3 儲存貯體名稱。:aws s3 cp AIoTnAWSCloud/lab/website/show_s3_image.html s3://BUCKET_NAME/
圖 19. 修改網頁所指定的圖片所在位置
再重新檢視一次網頁,就可以看到上傳的圖片內容了。
圖 20. 重新檢視網頁